package com.zsy.springframework.beans.xml;

import cn.hutool.core.util.StrUtil;
import com.zsy.springframework.beans.facotry.config.BeanDefinition;
import com.zsy.springframework.beans.facotry.config.BeanReference;
import com.zsy.springframework.beans.facotry.config.PropertyValue;
import com.zsy.springframework.beans.facotry.exception.BeansException;
import com.zsy.springframework.beans.facotry.jiekou.one.BeanDefinitionRegistry;
import com.zsy.springframework.beans.facotry.support.AbstractBeanDefinitionReader;
import com.zsy.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import com.zsy.springframework.resourceloader.jiekou.Resource;
import com.zsy.springframework.resourceloader.jiekou.ResourceLoader;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

//resourceloader加载进来之后是xml文件的话，需要走这个解析的
//将xml标签对应到beandefinition当中
//上面有个接口 BeanDefinitionReader 可以根据情况进行加载选择
//不一定都是xml的文件
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    //因为父类写了两个非空参数的构造，所以默认的空参构造不生效，
    // 所以子类继承后，无法调用父类的默认构造

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader loader) {
        super(registry, loader);
    }

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

    //下面的方法都是通过这个方法来操作的，无非就是多遍历几次操作
    //这种操作在源码中很常见，提高代码的复用
    @Override
    public void loadBeanDefinitions(Resource resource) throws BeansException {
        try (InputStream inputStream = resource.getInputStream()) {
            doLoadBeanDefinitions(inputStream);
        } catch (IOException | ClassNotFoundException | DocumentException e) {
            throw new BeansException("IOException parsing XML document from " + resource, e);
        }
    }

    @Override
    public void loadBeanDefinitions(Resource... resources) throws BeansException {
        for (Resource resource : resources) {
            loadBeanDefinitions(resource);
        }
    }

    @Override
    public void loadBeanDefinitions(String path) throws BeansException {
        ResourceLoader loader = getResourceLoader();
        Resource resource = loader.getResource(path);
        loadBeanDefinitions(resource);
    }

    @Override
    public void loadBeanDefinitions(String... paths) throws BeansException {
        for (String path : paths) {
            loadBeanDefinitions(path);
        }
    }
//这里也有变化了 注解的是之前的，
//    //具体就是从xml文件中读取资源
//    private void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
//        Document doc = XmlUtil.readXML(inputStream);
//        Element root = doc.getDocumentElement();
//        NodeList childNodes = root.getChildNodes();
//
//        for (int i = 0; i < childNodes.getLength(); i++) {
//            // 判断元素
//            if (!(childNodes.item(i) instanceof Element)) continue;
//            // 判断对象
//            if (!"bean".equals(childNodes.item(i).getNodeName())) continue;
//
//            // 解析标签
//            Element bean = (Element) childNodes.item(i);
//            String id = bean.getAttribute("id");
//            String name = bean.getAttribute("name");
//            String className = bean.getAttribute("class");
//            // 获取 Class，方便获取类中的名称
//            Class<?> clazz = Class.forName(className);
//            // 优先级 id > name
//            String beanName = StrUtil.isNotEmpty(id) ? id : name;
//            if (StrUtil.isEmpty(beanName)) {
//                beanName = StrUtil.lowerFirst(clazz.getSimpleName());
//            }
//
//            // 定义Bean
//            BeanDefinition beanDefinition = new BeanDefinition(clazz);
//            // 读取属性并填充
//            for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
//                if (!(bean.getChildNodes().item(j) instanceof Element)) continue;
//                if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) continue;
//                // 解析标签：property
//                Element property = (Element) bean.getChildNodes().item(j);
//                String attrName = property.getAttribute("name");
//                String attrValue = property.getAttribute("value");
//                String attrRef = property.getAttribute("ref");
//                // 获取属性值：引入对象、值对象
//                //判断这个bean是否有人用过了
//                Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
//                // 创建属性信息
//                PropertyValue propertyValue = new PropertyValue(attrName, value);
//                beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
//            }
//            if (getRegistry().containsBeanDefinition(beanName)) {
//                throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
//            }
//            // 注册 BeanDefinition
//            getRegistry().registerBeanDefinition(beanName, beanDefinition);
//        }
//    }
protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException, DocumentException {
    SAXReader reader = new SAXReader();
    Document document = reader.read(inputStream);
    Element root = document.getRootElement();

    // 解析 context:component-scan 标签，扫描包中的类并提取相关信息，用于组装 BeanDefinition
    Element componentScan = root.element("component-scan");
    if (null != componentScan) {
        String scanPath = componentScan.attributeValue("base-package");
        if (StrUtil.isEmpty(scanPath)) {
            throw new BeansException("The value of base-package attribute can not be empty or null");
        }
        scanPackage(scanPath);
    }

    List<Element> beanList = root.elements("bean");
    for (Element bean : beanList) {

        String id = bean.attributeValue("id");
        String name = bean.attributeValue("name");
        String className = bean.attributeValue("class");
        String initMethod = bean.attributeValue("init-method");
        String destroyMethodName = bean.attributeValue("destroy-method");
        String beanScope = bean.attributeValue("scope");

        // 获取 Class，方便获取类中的名称
        Class<?> clazz = Class.forName(className);
        // 优先级 id > name
        String beanName = StrUtil.isNotEmpty(id) ? id : name;
        if (StrUtil.isEmpty(beanName)) {
            beanName = StrUtil.lowerFirst(clazz.getSimpleName());
        }

        // 定义Bean
        BeanDefinition beanDefinition = new BeanDefinition(clazz);
        beanDefinition.setInitMethodName(initMethod);
        beanDefinition.setDestroyMethodName(destroyMethodName);

        if (StrUtil.isNotEmpty(beanScope)) {
            beanDefinition.setScope(beanScope);
        }

        List<Element> propertyList = bean.elements("property");
        // 读取属性并填充
        for (Element property : propertyList) {
            // 解析标签：property
            String attrName = property.attributeValue("name");
            String attrValue = property.attributeValue("value");
            String attrRef = property.attributeValue("ref");
            // 获取属性值：引入对象、值对象
            Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
            // 创建属性信息
            PropertyValue propertyValue = new PropertyValue(attrName, value);
            beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
        }
        if (getRegistry().containsBeanDefinition(beanName)) {
            throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
        }
        // 注册 BeanDefinition
        getRegistry().registerBeanDefinition(beanName, beanDefinition);
    }
}



    //注解使用到的
    private void scanPackage(String scanPath) {
        String[] basePackages = StrUtil.splitToArray(scanPath, ',');
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(getRegistry());
        scanner.doScan(basePackages);
    }

}
